package com.bjsxt;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**TCP 一对多聊天服务器*/
/*有一个公共的数据缓冲区  当客户发送消息时，数据发送到公共缓冲区，接
 * 收消息的线程才启动，从公共缓冲区获取消息，再返回各个客户端*/
 //首先定义公共缓冲区，再编写接收客户端发送消息的线程类和 向客户端发送消息的线程类

/*接收客户端发送消息的线程类*/
class ReceiveMsg03 extends Thread{
    //把Socket对象传入来
    private Socket socket;
    public ReceiveMsg03(Socket socket){
        this.socket=socket;
    }

    @Override
    public void run() {
        this.receive03();
    }
    //接收客户端发送消息的方法
    private void receive03(){
        BufferedReader br = null;
        try{
            //定义读取流的对象  字节输入流转为字符输入流
            br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            while (true){
                String msg = br.readLine();
                //将消息写到公共区，因为接收消息与发送消息互斥 所以用synchronized 对象锁是字符串
                synchronized ("msg") {
                    ChartRoomServer03.buf = "[" + this.socket.getInetAddress() + "]" + " " + msg;
                    //当公共区接收到信息时，才可以发送给其它客户端
                    "msg".notifyAll();//唤醒向客户端发送信息的同步线程
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(this.socket !=null){
                try {
                    this.socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
/*向客户端发送消息的线程类*/
class SendMsg03 extends Thread{
    private Socket socket;
    public SendMsg03(Socket socket){
        this.socket=socket;
    }

    @Override
    public void run() {
        this.send03();
    }
    private void send03(){
        PrintWriter pw = null;
        try {
            //定义输出流对象  输出的是字符串，所以用字符流对象，不用转流
            pw = new PrintWriter(this.socket.getOutputStream());
            //可能不断发送信息，所以用无限循环
            while (true) {
                synchronized ("msg") {
                    //让发送消息的线程处于等状态，当接收到公共区有消息时才解除等待
                    "msg".wait();
                    //从公共缓冲区拿信息ChartRoomServer03.buf
                    pw.println(ChartRoomServer03.buf);
                    pw.flush();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(this.socket != null){
                try {
                    this.socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(pw != null){
                pw.close();
            }
        }
    }
}
public class ChartRoomServer03 {
    //定义公共数据区  公共数据区是唯一的，在成员变量加static 是字符串类型
    public static String buf;

    public static void main(String[] args) {
        //主线程作用：建立与客户端持续连接
        System.out.println("Chat Server Version 1.0");
        System.out.println("Listen at 8888.....");
        ServerSocket serverSocket = null;
        try{
            //实例化要监听的端口
            serverSocket = new ServerSocket(8888);
            while (true){
                Socket socket = serverSocket.accept();
                System.out.println("连接到"+socket.getInetAddress());
                new ReceiveMsg03(socket).start();
                new SendMsg03(socket).start();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
